home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlb20 / lib / doprnt.c < prev    next >
C/C++ Source or Header  |  1992-05-17  |  20KB  |  801 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. /*
  19.  * minorly customized for gcc lib
  20.  *    ++jrb
  21.  * and for the sfp004 as well as the TT's 68881
  22.  *      mjr++
  23.  */
  24.  
  25. #ifndef __NO_FLOAT__
  26. #if 0
  27. static unsigned long
  28.     __notanumber[2] = { 0x7fffffffL, 0xffffffffL }; /* ieee NAN */
  29. #define NAN  (*((double *)&__notanumber[0]))
  30. static unsigned long
  31.     __p_infinity[2] = { 0x7ff00000L, 0x00000000L }; /* ieee NAN */
  32. #define INF  (*((double *)&__p_infinity[0]))
  33. #endif
  34.  
  35. #define NAN_HI 0x7fffffffL
  36. #define NAN_LO 0xffffffffL
  37. #define INF_HI 0x7ff00000L
  38. #define INF_LO 0x00000000L
  39.  
  40. #endif /* __NO_FLOAT__ */
  41.  
  42. #ifdef LIBC_SCCS
  43. static char sccsid[] = "@(#)doprnt.c    5.37 (Berkeley) 3/26/89";
  44. #endif /* LIBC_SCCS */
  45.  
  46. #include <sys/types.h>
  47. #include <stdarg.h>
  48. #include <stdio.h>
  49. #include <ctype.h>
  50. #include <string.h>
  51. #include <limits.h>
  52. #include    <math.h>    /* mjr++    */
  53.  
  54. #ifndef __GNUC__    /* gcc lib has these typedefs in sys/types.h */
  55. #ifndef __MINT__    /* as does the MiNT library */
  56. typedef unsigned char u_char;
  57. typedef unsigned long u_long;
  58. #endif
  59. #endif
  60.  
  61. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  62. #define    MAXEXP        308
  63.  
  64. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  65. # define    MAXFRACT    39
  66. # define    MAXEXP        308
  67.  
  68. #if defined (__M68881__) && !defined (sfp004)
  69. #  include <math-68881.h>    /* mjr: use the inline functions    */
  70. #endif    __M68881__
  71.  
  72. #define    DEFPREC        6
  73.  
  74. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  75.  
  76. #define    PUTC(ch)     if( fputc(ch, fp) == EOF ) return EOF;
  77.  
  78. #define ARG(basetype) \
  79.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  80.         flags&SHORTINT ? (short basetype)va_arg(argp, short) : \
  81.         va_arg(argp, int)
  82.  
  83. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  84.  
  85. #define    todigit(c)    ((c) - '0')
  86. #define    tochar(n)    ((n) + '0')
  87.  
  88. #define    LONGINT        0x01        /* long integer */
  89. #define    LONGDBL        0x02        /* long double; unimplemented */
  90. #define    SHORTINT    0x04        /* short integer */
  91. #define    ALT        0x08        /* alternate form */
  92. #define    LADJUST        0x10        /* left adjustment */
  93. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  94. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  95.  
  96. #ifndef __NO_FLOAT__
  97. #define __FLOATS__ 1
  98. #endif
  99.  
  100. #ifdef __FLOATS__
  101. # include    "flonum.h"
  102. #  if __STDC__
  103. static char *exponent(char *, int, int);
  104. static char *round(double, int *, char *, char *, int, char *);
  105. static int  cvt(double, int, int, char *, int, char *, char *);
  106. #  else
  107. static char *exponent();
  108. static char *round();
  109. static int  cvt();
  110. #  endif
  111. #endif
  112.  
  113. #ifdef __GNUC__
  114. #ifdef __M68020__
  115.  
  116. #define _ICONV(NUMBER, BASE, BUF)                \
  117. {                                \
  118.   long i;                            \
  119.   do                                \
  120.     {                                \
  121.       __asm__ volatile                        \
  122.     ("divull %3,%0:%1"                    \
  123.      : "=d"((long)(NUMBER)), "=d"(i)            \
  124.      : "0"((long)(NUMBER)), "d"((long)(BASE)));        \
  125.       *--(BUF) = digs[i];                    \
  126.     }                                \
  127.   while (NUMBER);                        \
  128. }
  129.  
  130. #else /* !__M68020 */  
  131.  
  132. #define _ICONV(NUMBER, BASE, BUF)                 \
  133. {                                \
  134.                                 \
  135.     while((NUMBER) > 65535L)                    \
  136.     {                                \
  137.         extern unsigned long __udivsi3(); /* quot = d0, rem = d1 */ \
  138.         register long i __asm ("d1");                    \
  139.     __asm__ volatile("
  140.         movl    %3,sp@-;
  141.          movl    %2,sp@-;
  142.          jsr    ___udivsi3;
  143.          addqw    #8,sp;
  144.          movl    d0,%0"                    \
  145.              : "=r"((long)NUMBER), "=d"(i)            \
  146.          : "0"((long)NUMBER), "r"((long)BASE)        \
  147.              : "d0", "d1", "a0", "a1");            \
  148.         *--BUF = digs[i];                    \
  149.     }                                \
  150.     do                                 \
  151.     {                                \
  152.             short i;                        \
  153.         __asm__ volatile("
  154.          divu    %3,%2;
  155.          swap    %0;
  156.          movw    %0,%1;
  157.          clrw    %0;
  158.                 swap    %0"                    \
  159.              : "=d"((long)NUMBER), "=g"(i)            \
  160.          : "0"((long)NUMBER), "g"((short)BASE));    \
  161.         *--BUF = digs[i];                    \
  162.     } while(NUMBER);                        \
  163. }
  164.  
  165. #endif /* __M68020 */
  166.  
  167. #else /* !__GNUC__ */
  168.  
  169. #define _ICONV(NUMBER, BASE, BUF)                 \
  170.   do {                                \
  171.     *--(BUF) = digs[(NUMBER) % (BASE)];                \
  172.     (NUMBER) /= (BASE);                        \
  173.   } while (NUMBER);
  174.  
  175. #endif /* __GNUC__ */
  176.  
  177.  
  178. int _doprnt(fp, fmt0, argp)
  179.     register FILE *fp;
  180.     const char *fmt0;
  181.     va_list argp;
  182. {
  183.     register const u_char *fmt;    /* format string */
  184.     register int ch;    /* character from fmt */
  185.     register int cnt;    /* return value accumulator */
  186.     register int n;        /* random handy integer */
  187.     register char *t;    /* buffer pointer */
  188. #ifdef    __FLOATS__
  189. /*    double _double;        *//* double precision arguments %[eEfgG] */
  190.     union double_di _dd;    /* _double is #defined to be _dd later on */
  191. #endif    __FLOATS__
  192.     u_long _ulong;        /* integer arguments %[diouxX] */
  193.     short base;        /* base for [diouxX] conversion */
  194.     short dprec;        /* decimal precision in [diouxX] */
  195.     short fieldsz;        /* field size expanded by sign, etc */
  196.     short flags;        /* flags as above */
  197.     short fpprec;        /* `extra' floating precision in [eEfgG] */
  198.     short prec;        /* precision from format (%.3d), or -1 */
  199.     short realsz;        /* field size expanded by decimal precision */
  200.     short size;        /* size of converted field or string */
  201.     short width;        /* width from format (%8d), or 0 */
  202.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  203.     char softsign;        /* temporary negative sign for floats */
  204.     char *digs;        /* digits for [diouxX] conversion */
  205.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  206.  
  207.         t = buf;
  208.     fmt = (const u_char *) fmt0;
  209.     digs = "0123456789abcdef";
  210.     for (cnt = 0;; ++fmt) {
  211.         if (!(ch = *fmt))
  212.             return (cnt);
  213.         if (ch != '%') {
  214.             PUTC(ch);
  215.             cnt++;
  216.             continue;
  217.         }
  218.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  219.         prec = -1;
  220.         sign = '\0';
  221.  
  222. rflag:        switch (*++fmt) {
  223.         case ' ':
  224.             /*
  225.              * ``If the space and + flags both appear, the space
  226.              * flag will be ignored.''
  227.              *    -- ANSI X3J11
  228.              */
  229.             if (!sign)
  230.                 sign = ' ';
  231.             goto rflag;
  232.         case '#':
  233.             flags |= ALT;
  234.             goto rflag;
  235.         case '*':
  236.             /*
  237.              * ``A negative field width argument is taken as a
  238.              * - flag followed by a  positive field width.''
  239.              *    -- ANSI X3J11
  240.              * They don't exclude field widths read from args.
  241.              */
  242.             if ((width = (short)(va_arg(argp, int))) >= 0)
  243.                 goto rflag;
  244.             width = -width;
  245.             /* FALLTHROUGH */
  246.         case '-':
  247.             flags |= LADJUST;
  248.             goto rflag;
  249.         case '+':
  250.             sign = '+';
  251.             goto rflag;
  252.         case '.':
  253.             if (*++fmt == '*')
  254.                 n = va_arg(argp, int);
  255.             else {
  256.                 n = 0;
  257.                 while (isascii(*fmt) && isdigit(*fmt))
  258.                     n = TEN_MUL(n) + todigit(*fmt++);
  259.                 --fmt;
  260.             }
  261.             prec = n < 0 ? -1 : n;
  262.             goto rflag;
  263.         case '0':
  264.             /*
  265.              * ``Note that 0 is taken as a flag, not as the
  266.              * beginning of a field width.''
  267.              *    -- ANSI X3J11
  268.              */
  269.             flags |= ZEROPAD;
  270.             goto rflag;
  271.         case '1': case '2': case '3': case '4':
  272.         case '5': case '6': case '7': case '8': case '9':
  273.             n = 0;
  274.             do {
  275.                 n = TEN_MUL(n) + todigit(*fmt);
  276.             } while (isascii(*++fmt) && isdigit(*fmt));
  277.             width = n;
  278.             --fmt;
  279.             goto rflag;
  280.         case 'L':
  281.             flags |= LONGDBL;
  282.             goto rflag;
  283.         case 'h':
  284.             flags |= SHORTINT;
  285.             goto rflag;
  286.         case 'l':
  287.             flags |= LONGINT;
  288.             goto rflag;
  289.         case 'c':
  290.             *(t = buf) = va_arg(argp, int);
  291.             size = 1;
  292.             sign = '\0';
  293.             goto pforw;
  294.         case 'D':
  295.             flags |= LONGINT;
  296.             /*FALLTHROUGH*/
  297.         case 'd':
  298.         case 'i':
  299.             ARG(int);
  300.             if ((long)_ulong < 0) {
  301.                 _ulong = -_ulong;
  302.                 sign = '-';
  303.             }
  304.             base = 10;
  305.             goto number;
  306. #ifdef __FLOATS__
  307.         case 'e':
  308.         case 'E':
  309.         case 'f':
  310.         case 'g':
  311.         case 'G':
  312.  
  313. /* mjr: check for NANs */
  314. #define    _double _dd.d
  315.             _double = va_arg(argp, double);
  316.             if (_dd.i[0] == NAN_HI)
  317.             {
  318.                 t = buf;
  319.                 t = strcpy(t, "NaN");
  320.                 size = strlen(t);
  321.                 goto pforw;
  322.             }
  323.             /*
  324.              * don't do unrealistic precision; just pad it with
  325.              * zeroes later, so buffer size stays rational.
  326.              */
  327.             if (prec > MAXFRACT) {
  328.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  329.                     fpprec = prec - MAXFRACT;
  330.                 prec = MAXFRACT;
  331.             }
  332.             else if (prec == -1)
  333.                 prec = DEFPREC;
  334.             /*
  335.              * softsign avoids negative 0 if _double is < 0 and
  336.              * no significant digits will be shown
  337.              */
  338.             if (_double < 0) {
  339.                 softsign = '-';
  340.                 _double = -_double;
  341.             }
  342.             else
  343.                 softsign = 0;
  344. /* mjr: check for +-INFINITY */
  345.             if (((unsigned long)_dd.i[0] == INF_HI) &&
  346.                 ((unsigned long)_dd.i[1] == INF_LO))
  347.               {
  348.                 t = buf;
  349.                 if(softsign == 0)
  350.                 t = strcpy(t, "+Inf");
  351.                 else
  352.                 t = strcpy(t, "-Inf");
  353.                 size = strlen(t);
  354.                 goto pforw;
  355.             }
  356.             /*
  357.              * cvt may have to round up past the "start" of the
  358.              * buffer, i.e. ``printf("%.2f", (double)9.999);'';
  359.              * if the first char isn't '\0', it did.
  360.              */
  361.             *buf = '\0';
  362.             size = cvt(_double, (int)prec, (int)flags, &softsign,
  363.                    *fmt, buf, buf + (int)sizeof(buf)); 
  364.             if (softsign)
  365.                 sign = '-';
  366.             t = *buf ? buf : buf + 1;
  367.             goto pforw;
  368. #endif /* __FLOATS__ */
  369.         case 'n':
  370.             if (flags & LONGINT)
  371.                 *va_arg(argp, long *) = cnt;
  372.             else if (flags & SHORTINT)
  373.                 *va_arg(argp, short *) = cnt;
  374.             else
  375.                 *va_arg(argp, int *) = cnt;
  376.             break;
  377.         case 'O':
  378.             flags |= LONGINT;
  379.             /*FALLTHROUGH*/
  380.         case 'o':
  381.             ARG(unsigned);
  382.             base = 8;
  383.             goto nosign;
  384.         case 'p':
  385.             /*
  386.              * ``The argument shall be a pointer to void.  The
  387.              * value of the pointer is converted to a sequence
  388.              * of printable characters, in an implementation-
  389.              * defined manner.''
  390.              *    -- ANSI X3J11
  391.              */
  392.             /* NOSTRICT */
  393.             _ulong = (u_long)va_arg(argp, void *);
  394.             base = 16;
  395.             goto nosign;
  396.         case 's':
  397.             if (!(t = va_arg(argp, char *)))
  398.                 t = "(null)";
  399.             if (prec >= 0) {
  400.                 /*
  401.                  * can't use strlen; can only look for the
  402.                  * NUL in the first `prec' characters, and
  403.                  * strlen() will go further.
  404.                  */
  405. #ifdef __STDC__
  406.                 char *p;
  407.                 void *memchr(const void *, int, size_t);
  408. #else
  409.                 char *p, *memchr();
  410. #endif
  411.  
  412.                 if (p = (char *)memchr(t, 0, (size_t)prec)) {
  413.                     size = p - t;
  414.                     if (size > prec)
  415.                         size = prec;
  416.                 } else
  417.                     size = prec;
  418.             } else
  419.                 size = (int)strlen(t);
  420.             sign = '\0';
  421.             goto pforw;
  422.         case 'U':
  423.             flags |= LONGINT;
  424.             /*FALLTHROUGH*/
  425.         case 'u':
  426.             ARG(unsigned);
  427.             base = 10;
  428.             goto nosign;
  429.         case 'X':
  430.             digs = "0123456789ABCDEF";
  431.             /* FALLTHROUGH */
  432.         case 'x':
  433.             ARG(unsigned);
  434.             base = 16;
  435.             /* leading 0x/X only if non-zero */
  436.             if (flags & ALT && _ulong != 0)
  437.                 flags |= HEXPREFIX;
  438.  
  439.             /* unsigned conversions */
  440. nosign:            sign = '\0';
  441.             /*
  442.              * ``... diouXx conversions ... if a precision is
  443.              * specified, the 0 flag will be ignored.''
  444.              *    -- ANSI X3J11
  445.              */
  446. number:            if ((dprec = prec) >= 0)
  447.                 flags &= ~ZEROPAD;
  448.  
  449.             /*
  450.              * ``The result of converting a zero value with an
  451.              * explicit precision of zero is no characters.''
  452.              *    -- ANSI X3J11
  453.              */
  454.             t = buf + BUF;
  455.             if (_ulong != 0 || prec != 0) {
  456.                 _ICONV(_ulong, base, t);
  457.                 digs = "0123456789abcdef";
  458.                 if (flags & ALT && base == 8 && *t != '0')
  459.                     *--t = '0'; /* octal leading 0 */
  460.             }
  461.             size = buf + BUF - t;
  462.  
  463. pforw:
  464.             /*
  465.              * All reasonable formats wind up here.  At this point,
  466.              * `t' points to a string which (if not flags&LADJUST)
  467.              * should be padded out to `width' places.  If
  468.              * flags&ZEROPAD, it should first be prefixed by any
  469.              * sign or other prefix; otherwise, it should be blank
  470.              * padded before the prefix is emitted.  After any
  471.              * left-hand padding and prefixing, emit zeroes
  472.              * required by a decimal [diouxX] precision, then print
  473.              * the string proper, then emit zeroes required by any
  474.              * leftover floating precision; finally, if LADJUST,
  475.              * pad with blanks.
  476.              */
  477.  
  478.             /*
  479.              * compute actual size, so we know how much to pad
  480.              * fieldsz excludes decimal prec; realsz includes it
  481.              */
  482.             fieldsz = size + fpprec;
  483.             if (sign)
  484.                 fieldsz++;
  485.             if (flags & HEXPREFIX)
  486.                 fieldsz += 2;
  487.             realsz = dprec > fieldsz ? dprec : fieldsz;
  488.  
  489.             /* right-adjusting blank padding */
  490.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  491.                 for (n = realsz; n < width; n++)
  492.                     PUTC(' ');
  493.             /* prefix */
  494.             if (sign)
  495.                 PUTC(sign);
  496.             if (flags & HEXPREFIX) {
  497.                 PUTC('0');
  498.                 PUTC((char)*fmt);
  499.             }
  500.             /* right-adjusting zero padding */
  501.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  502.                 for (n = realsz; n < width; n++)
  503.                     PUTC('0');
  504.             /* leading zeroes from decimal precision */
  505.             for (n = fieldsz; n < dprec; n++)
  506.                 PUTC('0');
  507.  
  508.             /* the string or number proper */
  509.             for (n = size; --n >= 0; )
  510.                 PUTC(*t++);
  511.             /* trailing f.p. zeroes */
  512.             while (--fpprec >= 0)
  513.                 PUTC('0');
  514.             /* left-adjusting padding (always blank) */
  515.             if (flags & LADJUST)
  516.                 for (n = realsz; n < width; n++)
  517.                     PUTC(' ');
  518.             /* finally, adjust cnt */
  519.             cnt += width > realsz ? width : realsz;
  520.             break;
  521.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  522.             return (cnt);
  523.         default:
  524.             PUTC((char)*fmt);
  525.             cnt++;
  526.         }
  527.     }
  528.     /* NOTREACHED */
  529. }
  530.  
  531. #ifdef __FLOATS__
  532. static int
  533. cvt(number,prec,flags, signp, fmtch, startp, endp)
  534.     double number;
  535.     register int prec;
  536.     int flags;
  537.     int fmtch;
  538.     char *signp, *startp, *endp;
  539. {
  540.     register char *p, *t;
  541.     register double fract;
  542.     int dotrim, expcnt, gformat;
  543.     double integer, tmp, modf __PROTO((double, double *));
  544.     char *exponent __PROTO((char *, int, int)),
  545.          *round __PROTO((double, int *, char *, char *, int, char *));
  546.  
  547.     dotrim = expcnt = gformat = 0;
  548.     fract = modf(number, &integer);
  549.  
  550.     /* get an extra slot for rounding. */
  551.     t = ++startp;
  552.  
  553.     /*
  554.      * get integer portion of number; put into the end of the buffer; the
  555.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  556.      */
  557.     for (p = endp - 1; integer; ++expcnt) {
  558.         tmp = modf(integer / 10, &integer);
  559.         *p-- = tochar((int)((tmp + .01) * 10));
  560.     }
  561.     switch(fmtch) {
  562.     case 'f':
  563.         /* reverse integer into beginning of buffer */
  564.         if (expcnt)
  565.             for (; ++p < endp; *t++ = *p);
  566.         else
  567.             *t++ = '0';
  568.         /*
  569.          * if precision required or alternate flag set, add in a
  570.          * decimal point.
  571.          */
  572.         if (prec || flags&ALT)
  573.             *t++ = '.';
  574.         /* if requires more precision and some fraction left */
  575.         if (fract) {
  576.             if (prec)
  577.                 do {
  578.                     fract = modf(fract * 10, &tmp);
  579.                     *t++ = tochar((int)tmp);
  580.                 } while (--prec && fract);
  581.             if (fract)
  582.                 startp = round(fract, (int *)NULL, startp,
  583.                     t - 1, (char)0, signp);
  584.         }
  585.         for (; prec--; *t++ = '0');
  586.         break;
  587.     case 'e':
  588.     case 'E':
  589. eformat:    if (expcnt) {
  590.             *t++ = *++p;
  591.             if (prec || flags&ALT)
  592.                 *t++ = '.';
  593.             /* if requires more precision and some integer left */
  594.             for (; prec && ++p < endp; --prec)
  595.                 *t++ = *p;
  596.             /*
  597.              * if done precision and more of the integer component,
  598.              * round using it; adjust fract so we don't re-round
  599.              * later.
  600.              */
  601.             if (!prec && ++p < endp) {
  602.                 fract = 0;
  603.                 startp = round((double)0, &expcnt, startp,
  604.                     t - 1, *p, signp);
  605.             }
  606.             /* adjust expcnt for digit in front of decimal */
  607.             --expcnt;
  608.         }
  609.         /* until first fractional digit, decrement exponent */
  610.         else if (fract) {
  611.             /* adjust expcnt for digit in front of decimal */
  612.             for (expcnt = -1;; --expcnt) {
  613.                 fract = modf(fract * 10, &tmp);
  614.                 if (tmp)
  615.                     break;
  616.             }
  617.             *t++ = tochar((int)tmp);
  618.             if (prec || flags&ALT)
  619.                 *t++ = '.';
  620.         }
  621.         else {
  622.             *t++ = '0';
  623.             if (prec || flags&ALT)
  624.                 *t++ = '.';
  625.         }
  626.         /* if requires more precision and some fraction left */
  627.         if (fract) {
  628.             if (prec)
  629.                 do {
  630.                     fract = modf(fract * 10, &tmp);
  631.                     *t++ = tochar((int)tmp);
  632.                 } while (--prec && fract);
  633.             if (fract)
  634.                 startp = round(fract, &expcnt, startp,
  635.                     t - 1, (char)0, signp);
  636.         }
  637.         /* if requires more precision */
  638.         for (; prec--; *t++ = '0');
  639.  
  640.         /* unless alternate flag, trim any g/G format trailing 0's */
  641.         if (gformat && !(flags&ALT)) {
  642.             while (t > startp && *--t == '0');
  643.             if (*t == '.')
  644.                 --t;
  645.             ++t;
  646.         }
  647.         t = exponent(t, expcnt, fmtch);
  648.         break;
  649.     case 'g':
  650.     case 'G':
  651.         /* a precision of 0 is treated as a precision of 1. */
  652.         if (!prec)
  653.             ++prec;
  654.         /*
  655.          * ``The style used depends on the value converted; style e
  656.          * will be used only if the exponent resulting from the
  657.          * conversion is less than -4 or greater than the precision.''
  658.          *    -- ANSI X3J11
  659.          */
  660.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  661.             /*
  662.              * g/G format counts "significant digits, not digits of
  663.              * precision; for the e/E format, this just causes an
  664.              * off-by-one problem, i.e. g/G considers the digit
  665.              * before the decimal point significant and e/E doesn't
  666.              * count it as precision.
  667.              */
  668.             --prec;
  669.             fmtch -= 2;        /* G->E, g->e */
  670.             gformat = 1;
  671.             goto eformat;
  672.         }
  673.         /*
  674.          * reverse integer into beginning of buffer,
  675.          * note, decrement precision
  676.          */
  677.         if (expcnt)
  678.             for (; ++p < endp; *t++ = *p, --prec);
  679.         else
  680.             *t++ = '0';
  681.         /*
  682.          * if precision required or alternate flag set, add in a
  683.          * decimal point.  If no digits yet, add in leading 0.
  684.          */
  685.         if (prec || flags&ALT) {
  686.             dotrim = 1;
  687.             *t++ = '.';
  688.         }
  689.         else
  690.             dotrim = 0;
  691.         /* if requires more precision and some fraction left */
  692.         if (fract) {
  693.             if (prec) {
  694.                 if (0 == expcnt) {
  695.                     /* if no significant digits yet */
  696.                     do {
  697.                         fract = modf(fract * 10, &tmp);
  698.                         *t++ = tochar((int)tmp);
  699.                     } while(!tmp);
  700.                     prec--;
  701.                 }
  702.                 while (prec && fract) {
  703.                     fract = modf(fract * 10, &tmp);
  704.                     *t++ = tochar((int)tmp);
  705.                     prec--;
  706.                 }
  707.             }
  708.             if (fract)
  709.                 startp = round(fract, (int *)NULL, startp,
  710.                     t - 1, (char)0, signp);
  711.         }
  712.         /* alternate format, adds 0's for precision, else trim 0's */
  713.         if (flags&ALT)
  714.             for (; prec--; *t++ = '0');
  715.         else if (dotrim) {
  716.             while (t > startp && *--t == '0');
  717.             if (*t != '.')
  718.                 ++t;
  719.         }
  720.     }
  721.     return((int)(t - startp));
  722. }
  723.  
  724. static char *
  725. round(fract, exp, start, end, ch, signp)
  726.     double fract;
  727.     int *exp;
  728.     register char *start, *end;
  729.     int ch;
  730.     char *signp;
  731. {
  732.     double tmp;
  733.  
  734.     if (fract)
  735.         (void)modf(fract * 10, &tmp);
  736.     else
  737.         tmp = todigit(ch);
  738.     if (tmp > 4)
  739.         for (;; --end) {
  740.             if (*end == '.')
  741.                 --end;
  742.             if (++*end <= '9')
  743.                 break;
  744.             *end = '0';
  745.             if (end == start) {
  746.                 if (exp) {    /* e/E; increment exponent */
  747.                     *end = '1';
  748.                     ++*exp;
  749.                 }
  750.                 else {        /* f; add extra digit */
  751.                     *--end = '1';
  752.                     --start;
  753.                 }
  754.                 break;
  755.             }
  756.         }
  757.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  758.     else if (*signp == '-')
  759.         for (;; --end) {
  760.             if (*end == '.')
  761.                 --end;
  762.             if (*end != '0')
  763.                 break;
  764.             if (end == start)
  765.                 *signp = 0;
  766.         }
  767.     return(start);
  768. }
  769.  
  770. static char *
  771. exponent(p, exp, fmtch)
  772.     register char *p;
  773.     register int exp;
  774.     int fmtch;
  775. {
  776.     register char *t;
  777.     char expbuf[MAXEXP];
  778.  
  779.     *p++ = fmtch;
  780.     if (exp < 0) {
  781.         exp = -exp;
  782.         *p++ = '-';
  783.     }
  784.     else
  785.         *p++ = '+';
  786.     t = expbuf + MAXEXP;
  787.     if (exp > 9) {
  788.         do {
  789.             *--t = tochar(exp % 10);
  790.         } while ((exp /= 10) > 9);
  791.         *--t = tochar(exp);
  792.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  793.     }
  794.     else {
  795.         *p++ = '0';
  796.         *p++ = tochar(exp);
  797.     }
  798.     return(p);
  799. }
  800. #endif __FLOATS__
  801.